<template>
  <el-container>
    <el-aside>
      组件选择
      <div v-for="(item, key) in listLeft" :key="key">
        <draggable tag="div" :list="[item]" v-bind="dragOptions1" @start="isDragging = true" @end="isDragging = false">
          <el-card> {{ item.tag }} </el-card>
        </draggable>
      </div>
    </el-aside>

    <el-main>
      布局 <el-button icon="el-icon-view" type="text" @click="renderJsonConfig"></el-button>

      <draggable class="dragArea" tag="ul" :list="listRight" @add="deepClone" v-bind="dragOptions2">
        <li v-for="el in listRight" :key="el.ref">
          <el-card>
            {{ el.tag }}
            <el-button icon="el-icon-edit" type="text" @click="openJson(el)"></el-button>
            <el-button icon="el-icon-delete" type="text" @click="deleteJson(el)"></el-button>
            <r-nested-draggable v-if="el.children" :children="el.children" :deepClone="deepClone" :openJson="openJson" :deleteJson="deleteJson" v-bind="dragOptions2" />
          </el-card>
        </li>
      </draggable>
    </el-main>

    <r-displayer :value="listRight" title="JSON" style="max-width: 20%" />

    <el-drawer :title="editingJson.tag" :visible.sync="drawerVisible" direction="rtl" :wrapperClosable="false" size="50%">
      <el-card>
        <el-form :inline="true" :model="editingJson" label-width="150px">
          <el-divider content-position="left">attrs</el-divider>
          <el-form-item label="ref">
            <el-input v-model="editingJson.ref" placeholder="ref"></el-input>
          </el-form-item>

          <el-form-item label="style">
            <el-input v-model="editingJson.style" placeholder="style"></el-input>
          </el-form-item>

          <el-form-item label="class">
            <el-input v-model="editingJson.class" placeholder="class"></el-input>
          </el-form-item>
          <el-divider content-position="left">props</el-divider>

          <el-form-item v-for="p in editingJson.props" :key="'props.' + p.prop" :label="p.prop + '.' + p.type">
            <el-switch v-model="p.source" active-text="输入确定值" inactive-text="继续传参"> </el-switch>

            <el-input v-model="p.name" :placeholder="p.prop + '.name'"></el-input>
            <el-input type="textarea" v-model="p.value" :placeholder="p.prop + '.value'"></el-input>
          </el-form-item>
          <el-divider content-position="left">evnets</el-divider>
          <el-form-item v-for="e in editingJson.events" :key="'events.' + e.event" :label="e.event">
            <el-switch v-model="e.source" active-text="自定义处理" inactive-text="继续监听"> </el-switch>
            <el-card>
              <el-input v-model="e.func" :placeholder="e.event + '.func'" style="width: 50%">
                <template slot="prepend">function </template>
              </el-input>
              <el-input v-model="e.args" :readonly="true" style="width: 50%">
                <template slot="prepend"> (</template>
                <template slot="append">) </template>
              </el-input>
              <el-input type="textarea" v-model="e.content" :placeholder="e.event">
                <template slot="prefix"> {</template>
                <template slot="append">}</template>
              </el-input>
            </el-card>
          </el-form-item>
        </el-form>

        <div style="text-align: center">
          <el-button @click="drawerVisible = false">cancel</el-button>
          <el-button type="primary" @click="renderJsonConfig">render</el-button>
        </div>
      </el-card>
    </el-drawer>

    <el-dialog :visible.sync="dialogVisible" width="90%">
      <r-code-viewer :componentConfig="componentConfig" @codeChange="onCodeChange"> </r-code-viewer>
    </el-dialog>
  </el-container>
</template>
 
<script>
import draggable from 'vuedraggable'

import { newComponentJson, genComponentJson, parseComponentByJson, parseComponentByStr } from '../util/templateUtil.js'
import * as config from '../components/config'
const configArr = (() => {
  let arr = []
  for (let key in config) {
    arr.push(config[key]())
  }
  return arr
})()

function setRef(list, refIndex) {
  if (!list || list.length <= 0) {
    return false
  }
  for (let el of list) {
    if (!el.ref) {
      el.ref = el.tag + refIndex
      return true
    }
    if (setRef(el.children, refIndex)) {
      return true
    }
  }
  return false
}

function deleteByRef(list, ref) {
  let newList = [...list.filter((e) => e.ref !== ref)]
  newList.forEach((e) => e.children && (e.children = deleteByRef(e.children, ref)))
  return newList
}

export default {
  name: 'dragDemo',
  components: {
    draggable
  },
  data() {
    return {
      componentConfig: undefined,
      dialogVisible: false,
      drawerVisible: false,
      editingJson: {},
      isDragging: false,
      refIndex: 1,
      listLeft: configArr,
      listRight: []
    }
  },
  computed: {
    dragOptions1() {
      return {
        animation: 200,
        group: {
          name: 'component',
          pull: 'clone',
          put: false
        },
        ghostClass: 'ghost'
      }
    },
    dragOptions2() {
      return {
        animation: 200,
        group: {
          name: 'component'
        },
        disabled: false,
        ghostClass: 'ghost'
      }
    }
  },
  methods: {
    deepClone(evt) {
      // json深拷贝一次
      const listString = JSON.stringify(this.listRight)
      const list = JSON.parse(listString)
      setRef(list, this.refIndex++)
      this.listRight = list
    },
    openJson(json) {
      this.editingJson = json
      this.drawerVisible = true
    },
    deleteJson(json) {
      this.listRight = deleteByRef(this.listRight, json.ref)
    },
    changeComponent(componentJson) {
      this.componentConfig = parseComponentByJson(componentJson)
      console.log(JSON.stringify(newComponentJson(this.listRight[0], ''), null, 2))
    },
    onCodeChange(sourceCode) {
      if (!!sourceCode && sourceCode != this.componentConfig.sourceCode) {
        this.componentConfig = { ...parseComponentByStr(sourceCode), json: this.componentConfig.json }
      }
    },
    renderJsonConfig() {
      this.changeComponent(this.listRight[0])
      this.dialogVisible = true
    }
  }
}
</script>
 
 <style scope>
.dragArea {
  min-height: 300px;
  outline: 1px dashed;
}
ul li {
  list-style-type: none;
}
</style>
